﻿using System;
using System.Data.Entity;
using System.Threading;
using YiDa.Domain.Repositories;
using YiDa.Events.Bus;

namespace YiDa.Repository.EntityFramework
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <remarks>
    /// 
    /// </remarks>
    public class EntityFrameworkRepositoryContext<T> : RepositoryContext, IEntityFrameworkRepositoryContext where T : DbContext
    {
        private readonly ThreadLocal<T> localCtx = new ThreadLocal<T>(() => (T)Activator.CreateInstance(typeof(T)));

        public EntityFrameworkRepositoryContext(IBus bus) : base(bus) { }

        public override void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
        {
            this.DumpPendingEvents(obj);
            localCtx.Value.Set<TAggregateRoot>().Remove(obj);
            Committed = false;
        }

        public override void RegisterModified<TAggregateRoot>(TAggregateRoot obj)                               //EF应该不需要校验集合中是否存在，以避免引发不必要的数据库访问，但要求前端调用时必需保证正确的调用
        {
            this.DumpPendingEvents(obj);
            localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Modified;
            Committed = false;
        }

        public override void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
        {
            this.DumpPendingEvents(obj);
            localCtx.Value.Set<TAggregateRoot>().Add(obj);
            Committed = false;
        }

        public override void Rollback()
        {
            Committed = false;
        }

        protected override void DoCommit()
        {
            if (!Committed)
            {
                var validationErrors = localCtx.Value.GetValidationErrors();
                var count = localCtx.Value.SaveChanges();
                Committed = true;
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (!Committed)
                {
                    Commit();
                }
                localCtx.Value.Dispose();
                localCtx.Dispose();
                base.Dispose(disposing);
            }
        }

        #region IEntityFrameworkRepositoryContext Members

        public DbContext Context
        {
            get { return localCtx.Value; }
        }

        #endregion
    }
}
